#pragma once
#include <iostream>
#include <vector>
#include <string>
#include <sstream>
#include <string>
#include <memory>
#include <fstream>

#include "log.hpp"
#include <unordered_map>

#include "log.hpp"
static const std::string SEP = "\r\n";
static const std::string homeage = "index.html";
static const std::string filesuffixsep = ".";
static const std::string header_sep = ": ";
static const std::string wwwroot = "wwwroot";
static const std::string httpversion = "HTTP/1.0";
static const std::string space = " ";
static const std::string args_sep = "?";
class http_request;
class http_response;
using func_t = std::function<std::shared_ptr<http_response>(std::shared_ptr<http_request>)>;
class http_request
{
private:
    std::string get_one_line(std::string &request)
    {
        if (request.empty())
            return request; // 当请求为空时，返回空
        auto pos = request.find(SEP);
        if (pos == std::string::npos)
            return std::string(); // 出错返回空

        std::string line = request.substr(0, pos);
        request.erase(0, pos + SEP.size());
        return line.empty() ? SEP : line; // 返回非空,当找到SEP但是line为空时，读到空行，当line不为空时，读到正常行
    }
    bool parse_header_help(std::string &header, std::string *k, std::string *v)
    {
        auto pos = header.find(header_sep);
        if (pos == std::string::npos)
        {
            return false;
        }
        *k = header.substr(0, pos);
        *v = header.substr(pos + header_sep.size());
        return true;
    }

public:
    http_request() : _blank_line(SEP), _path(wwwroot)
    {
    }
    bool parse_req_line()
    {
        if (_req_line.empty())
            return false;
        std::stringstream ss(_req_line);
        ss >> _method >> _url >> _version;
        if (strcasecmp("get", _method.c_str()) == 0)
        {
            auto pos = _url.find(args_sep);
            // index.html?use=zhangsan&passwd=123456
            if (pos != std::string::npos) // 判断当为get方法时，url是否有参数
            {
                LOG(INFO, "change begin,url: %s\n", _url.c_str());
                _args = _url.substr(pos + args_sep.size()); // 获取url中的参数
                _url.resize(pos);
                LOG(INFO, "change done,url: %s,_args:%s\n", _url.c_str(), _args.c_str());
            }
        }
        _path += _url;
        LOG(DEBUG, "url: %s\n", _url.c_str());
        // 判断请求的是否是'/'目录,如果是，请求目录加上主页
        if (_path[_path.size() - 1] == '/')
        {
            _path += homeage;
        }
        auto pos = _path.rfind(filesuffixsep);
        if (pos == std::string::npos)
        {
            _suffix = ".unknown";
        }
        else
        {
            _suffix = _path.substr(0, pos);
        }
        LOG(INFO, "client wang get %s\n", _path.c_str());
        return true;
    }
    std::string path()
    {
        return _path;
    }
    std::string suffix()
    {
        return _suffix;
    }
    bool is_execute()
    {
        return !_args.empty() || !_req_text.empty();
    }
    std::string args()
    {
        return _args;
    }
    std::string text()
    {
        return _req_text;
    }
    std::string method()
    {
        return _method;
    }
    bool parse_header()
    {
        for (auto &header : _req_header)
        {
            std::string k, v;
            if (parse_header_help(header, &k, &v))
            {
                _headers.insert(std::make_pair(k, v));
            }
        }
        return true;
    }

    // 反序列化
    void deserialization(std::string &reqstr)
    {
        _req_line = get_one_line(reqstr);
        while (true)
        {
            std::string line = get_one_line(reqstr);
            if (line.empty())
            {
                break;
            }
            else if (line == SEP)
            {
                _req_text = reqstr;
                break;
            }
            else
            {
                _req_header.emplace_back(line);
            }
        }
        parse_req_line();
        parse_header();
    }
    void print()
    {
        std::cout << "=====" << _req_line << std::endl;
        for (auto &header : _req_header)
        {
            std::cout << "****" << header << std::endl;
        }
        std::cout << _blank_line << std::endl;
        std::cout << _req_text << std::endl;

        std::cout << "method ### " << _method << std::endl;
        std::cout << "url ### " << _url << std::endl;
        std::cout << "path ### " << _path << std::endl;
        std::cout << "http_version ### " << _version << std::endl;
        for (auto &header : _headers)
        {
            std::cout << "@@@ " << header.first << " - " << header.second << std::endl;
        }
    }
    ~http_request()
    {
    }

private:
    // 原始协议内容
    std::string _req_line;                // 请求行
    std::vector<std::string> _req_header; // 请求报头
    std::string _blank_line;              // 空行
    std::string _req_text;                // 请求正文
    // 期望解析的结果
    std::string _method; // 请求方法
    std::string _url;
    std::string _version; // HTTP版本
    std::string _args;      //get方法的参数
    std::string _path;
    std::string _suffix; // 请求文件的后缀
    std::unordered_map<std::string, std::string> _headers;
};
class http_response
{
public:
    http_response() : _version(httpversion), _blank_line(SEP)
    {
    }
    // 添加状态行
    void add_status_line(int code, const std::string &desc)
    {
        _code = code;
        _desc = desc;
    }
    // 添加报头
    void add_header(const std::string &k, const std::string &v)
    {
        _headers[k] = v;
    }
    // 添加响应正文
    void add_text(const std::string &text)
    {
        _resp_text = text;
    }
    // 序列化
    std::string serialize()
    {
        std::string _status_line = _version + space + std::to_string(_code) + space + _desc + SEP;
        for (auto &header : _headers)
        {
            _resp_header.emplace_back(header.first + header_sep + header.second + SEP);
        }
        // 序列化
        std::string regstr = _status_line;
        for (auto &header : _resp_header)
        {
            regstr += header;
        }
        regstr += _blank_line;
        regstr += _resp_text;
        return regstr;
    }
    ~http_response()
    {
    }

private:
    // 构建应答的必要字段
    std::string _version;                                  // http版本
    int _code;                                             // 状态码
    std::string _desc;                                     // 状态描述
    std::unordered_map<std::string, std::string> _headers; // 响应正文
    // 应答结构化字段
    std::string _status_line;              // 状态行
    std::vector<std::string> _resp_header; // 响应报头
    std::string _blank_line;               // 空行
    std::string _resp_text;                // 响应正文
};
class factory
{
public:
    static std::shared_ptr<http_request> build_request_ptr()
    {
        return std::make_shared<http_request>();
    }
    static std::shared_ptr<http_response> build_response_ptr()
    {
        return std::make_shared<http_response>();
    }

private:
};
class http_server
{
public:
    http_server()
    {
        _mime_type.insert(std::make_pair(".html", "text/html"));
        _mime_type.insert(std::make_pair(".css", "text/css"));
        _mime_type.insert(std::make_pair(".jpg", "application/x-jpg"));
        _mime_type.insert(std::make_pair(".png", "application/x-png"));
        _mime_type.insert(std::make_pair(".unknown", "text/html"));

        _code_to_desc.insert(std::make_pair(100, "Continue"));
        _code_to_desc.insert(std::make_pair(200, "OK"));
        _code_to_desc.insert(std::make_pair(301, "Moved Permanently"));
        _code_to_desc.insert(std::make_pair(302, "Found"));
        _code_to_desc.insert(std::make_pair(404, "Not Found"));
        _code_to_desc.insert(std::make_pair(500, "Internal Server Error"));
    }
    void add_handler(const std::string functionname, func_t f)//当请求的是functionname文件时，执行func_t 方法
    {
        std::string key = wwwroot + functionname; // wwwroot/login
        _funcs[key] = f;
    }
    std::string read_file_content(const std::string &path, int *size)
    {
        // 要按照二进制打开
        std::ifstream in(path, std::ios::binary);
        if (!in.is_open())
        {
            return std::string();
        }
        in.seekg(0, in.end);
        int filesize = in.tellg();
        in.seekg(0, in.beg);

        std::string content;
        content.resize(filesize);
        in.read((char *)content.c_str(), filesize);
        in.close();
        *size = filesize;
        return content;
    }
    std::string handler_http_reqeust(std::string req)
    {
        // std::cout << "---------------------------------------" << std::endl;
        // std::cout << req;

        // std::string response = "HTTP/1.0 200 OK\r\n"; // 404 NOT Found
        // response += "\r\n";
        // response += "<html><body><h1>hello world, hello bite!</h1></body></html>";
        // return response;

        // auto request = factory::build_request_ptr();
        // auto response = factory::build_response_ptr();
        // request->deserialization(req);//反序列化
        // int contentsize = 0;
        // std::string text = read_file_content(request->path(),&contentsize);
        // std::string suffix = request->suffix();//请求文件的后缀,标识响应文件类别
        // int code = 200;
        // response->add_status_line(code,_code_to_desc[code]);
        // response->add_header("Content-Length",std::to_string(contentsize));
        // response->add_header("Content-Type",_mime_type[suffix]);
        // response->add_text(text);
        // return response->serialize();

        // auto request = factory::build_request_ptr();
        // request->deserialization(req);
        // auto response = factory::build_response_ptr();
        // // std::string newurl = "https://www.baidu.com/";
        // std::string newurl = "http://8.152.3.29:8888/2.html";
        auto request = factory::build_request_ptr();
        request->deserialization(req);//反序列化
        if (request->is_execute())//判断是否需要网页互动
        {
            auto response = _funcs[request->path()](request);//根据path查找_funcs中的方法
            return response->serialize();
        }
        else
        {
            auto response = factory::build_response_ptr();
            int code = 200;
            int contentsize = 0;
            std::string text = read_file_content(request->path(), &contentsize);
            if (text.empty())
            {
                code = 404;
                response->add_status_line(code, _code_to_desc[code]);
                std::string text404 = read_file_content("wwwroot/404.html", &contentsize);
                response->add_header("Content-Length", std::to_string(contentsize));
                response->add_header("Content-Type", _mime_type[".html"]);
                response->add_text(text404);
            }
            else
            {
                std::string suffix = request->suffix();
                response->add_status_line(code, _code_to_desc[code]);
                response->add_header("Content-Length", std::to_string(contentsize));
                response->add_header("Content-Type", _mime_type[suffix]);
                response->add_text(text);
            }
            return response->serialize();
        }
    }
    ~http_server()
    {
    }

private:
    std::unordered_map<std::string, std::string> _mime_type;
    std::unordered_map<int, std::string> _code_to_desc;
    std::unordered_map<std::string, func_t> _funcs;
};